package com.bruce.tool.logger.dubbo.filter;

import com.bruce.tool.common.util.string.JsonUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * @author bruce
 */
@Activate(group = {CommonConstants.CONSUMER, CommonConstants.PROVIDER})
public class DubboCallLogFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(DubboCallLogFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result;
        try {
            result = invoker.invoke(invocation);
            if(!result.hasException()) {
                String normalMessage = toJSonString(result.getValue());
                String formattedResultMessage = buildInvokeResultMessage(normalMessage, invoker, invocation);
                logger.info(formattedResultMessage);
                return result;
            }

            Throwable exception = result.getException();
            //
            if(isDeclaredException(exception, invoker, invocation)) {
                //输出声明的异常
                String errorMessage = "declared exception: " + exception.getMessage() + "(" + exception.getClass().getSimpleName() + ")";
                String formattedResultMessage = buildInvokeResultMessage(errorMessage, invoker, invocation);
                logger.warn(formattedResultMessage);
                return result;
            }
            //输出未声明的异常
            String formattedResultMessage = buildInvokeResultMessage("undeclared exception", invoker, invocation);
            logger.error(formattedResultMessage, exception);
        } catch (RpcException var11) {
            //输出Dubbo Rpc异常
            String formattedResultMessage = buildInvokeResultMessage("rpc exception", invoker, invocation);
            logger.error(formattedResultMessage, var11);
            throw var11;
        }

        return result;
    }

    /**判断是否是方法声明的异常**/
    private boolean isDeclaredException(Throwable exception, Invoker<?> invoker, Invocation invocation) {
        try {
            Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
            Class<?>[] exceptionClassses = method.getExceptionTypes();
            for (Class<?> exceptionClass : exceptionClassses) {
                if (exception.getClass().equals(exceptionClass)) {
                    return true;
                }
            }
        } catch (NoSuchMethodException e) {

        }
        return false;
    }

    /**构造dubbo调用日志内容**/
    private String buildInvokeResultMessage(String resultMessage, Invoker<?> invoker, Invocation invocation) {
        //接口类名(com.juma.xxx.xxx)
        String service = invoker.getInterface().getName();
        //方法名
        String method = invocation.getMethodName();
        //方法参数
        Object[] arguments = invocation.getArguments();

        return service + "#" + method
                + "(" + toJSonString(arguments)
                + ")||results: " + resultMessage
                ;
    }

    private String toJSonString(Object object) {
        try {
            return JsonUtils.objToStr(object);
        } catch (Exception e) {
            logger.error("parse object to jsonText error ", e);
        }
        return "jsonText parse error";
    }
}
